﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration.Provider;
using System.Runtime.Caching;

namespace Shop.Infrastructure.Caching
{
    public abstract class CacheProvider : ProviderBase
    {
        public virtual bool Add(CacheItem item, CacheItemPolicy policy)
        {
            return Add(item.Key, item.Value, policy, item.RegionName);
        }

        public virtual bool Add(string key, object value, DateTimeOffset absoluteExpiration, string regionName = null)
        {
            CacheItemPolicy policy = new CacheItemPolicy();
            policy.AbsoluteExpiration = absoluteExpiration;
            return Add(key, value, policy, regionName);
        }

        public virtual bool Add(string key, object value, TimeSpan slidingExpiration, string regionName = null)
        {
            CacheItemPolicy policy = new CacheItemPolicy();
            policy.SlidingExpiration = slidingExpiration;
            return Add(key, value, policy, regionName);
        }

        /// <summary>
        /// Tries to add the specified entry to the cache store.
        /// </summary>    
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="policy"></param>
        /// <param name="regionName"></param>
        /// <returns>True if add succeeded, or false if there is an already an entry in the cache that has the same key as item.</returns>
        public abstract bool Add(string key, object value, CacheItemPolicy policy, string regionName = null);

        public abstract void Clear(string regionName = null);

        public abstract bool Contains(string key, string regionName = null);

        public abstract CacheEntryChangeMonitor CreateCacheEntryChangeMonitor(IEnumerable<string> keys, string regionName = null);

        public abstract DefaultCacheCapabilities DefaultCacheCapabilities
        {
            get;
        }

        public abstract object Get(string key, string regionName = null);

        /// <summary>
        /// Gets the cached value. If not found, returns the default value of <typeparamref name="T"/>.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="regionName"></param>
        /// <returns></returns>
        public virtual T Get<T>(string key, string regionName = null)
        {
            object objVal = Get(key, regionName);
            if (objVal != null)
            {
                return (T)objVal;
            }
            return default(T);
        }

        /// <summary>
        /// Gets the cached value. If not found, returns the specified <paramref name="defaultValue"/>.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="defaultValue"></param>
        /// <param name="regionName"></param>
        /// <returns></returns>
        public virtual T Get<T>(string key, T defaultValue, string regionName = null)
        {
            object objVal = Get(key, regionName);
            if (objVal != null)
            {
                return (T)objVal;
            }
            return defaultValue;
        }

        public abstract CacheItem GetCacheItem(string key, string regionName = null);

        public virtual IDictionary<string, object> GetValues(IEnumerable<string> keys, string regionName = null)
        {
            IDictionary<string, object> keyValueBag = new Dictionary<string, object>();
            foreach (string key in keys)
            {
                object obj = Get(key, regionName);
                keyValueBag.Add(key, obj);
            }
            //
            return keyValueBag;
        }

        public abstract object Remove(string key, string regionName = null);

        /// <summary>
        /// Inserts a item to the cache store.
        /// </summary>
        /// <remarks>
        /// If an item that matches key does not exist in the cache, value and key are used to insert as a new cache entry. 
        /// If an item with a key that matches item exists, the cache entry is updated or overwritten by using value.
        /// </remarks>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="policy"></param>
        /// <param name="regionName"></param>
        public abstract void Set(string key, object value, CacheItemPolicy policy, string regionName = null);

        public virtual void Set(string key, object value, DateTimeOffset absoluteExpiration, string regionName = null)
        {
            CacheItemPolicy policy = new CacheItemPolicy();
            policy.AbsoluteExpiration = absoluteExpiration;
            Set(key, value, policy, regionName);
        }

        public virtual void Set(string key, object value, TimeSpan slidingExpiration, string regionName = null)
        {
            CacheItemPolicy policy = new CacheItemPolicy();
            policy.SlidingExpiration = slidingExpiration;
            Set(key, value, policy, regionName);
        }
    }
}
